package com.example.novelweb.service.impl;


import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.novelweb.common.BaseResponse;
import com.example.novelweb.common.ErrorCode;
import com.example.novelweb.common.ResultUtils;
import com.example.novelweb.constant.UserConstant;
import com.example.novelweb.exception.BusinessException;
import com.example.novelweb.exception.ThrowUtils;
import com.example.novelweb.mapper.UserMapper;
import com.example.novelweb.model.dto.user.UserLoginRequest;
import com.example.novelweb.model.dto.user.UserUpdateRequest;
import com.example.novelweb.model.entity.User;
import com.example.novelweb.model.vo.UserVO;
import com.example.novelweb.service.RedisService;
import com.example.novelweb.service.UserService;
import com.example.novelweb.utils.FileUtils;
import com.example.novelweb.utils.RegexUtils;
import com.example.novelweb.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
* @author PERSON
* @description 针对表【user(用户)】的数据库操作Service实现
* @createDate 2025-01-10 18:30:13
*/
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{


  @Resource
  private RedisService redisService;

  // public BaseResponse<Void> sendCode(String account);
  @Override
  public BaseResponse<String> sendCodeMock(String account) {
    // 校验手机号
    if(RegexUtils.isPhoneInvalid(account)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"手机号输入非法");
    }
    // 生成验证码
    String code = RandomUtil.randomNumbers(6);
    // 保存到 session(redis)
    redisService.setVarifyCode(account,code);

    // 发送验证码 (mock)
    log.debug("Send VerifyCode to {},VerifyCode: {}",account,code);

    return ResultUtils.success(code);
  }

  @Override
  public BaseResponse<String> login(UserLoginRequest userLoginRequest) {
    String account = userLoginRequest.getAccount();
    // root登录检测
    if(account.equals("root")) {
      return rootLogin(userLoginRequest.getCode());
    }
    // 校验手机号
    if(RegexUtils.isPhoneInvalid(account)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"手机号输入非法");
    }

    // 校验验证码
    String code = userLoginRequest.getCode();
    // get verify code from redis
    String cacheCode = redisService.getVarifyCode(account);

    if(cacheCode==null || !cacheCode.equals(code)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"验证码错误");
    }
    redisService.delVarifyCode(account);

    // 手机号是否已注册
    // myBatis-plus: query()
    User user = query().eq("account",account).one();
    if(user == null) {
      // 未注册: 进行注册
      user = newUser(account);
      boolean result = save(user);
      ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR);
    }

    // 未登录/登录过期  => saveUserVo
    // 已登录          => refreshToken
    String token = redisService.saveUserOrRefreshToken(account,user);

    return ResultUtils.success(token);
  }

  private BaseResponse<String> rootLogin(String pwd) {
    // 校验密码
    User root = query().eq("account","root").one();
    String truePwd = root.getPassword();
    if(!truePwd.equals(pwd)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"账号密码错误");
    }
    String  token = redisService.saveUserOrRefreshToken("root",root);
    return  ResultUtils.success(token);
  }


  @Override
  public BaseResponse<Boolean> logout(HttpServletRequest httpServletRequest) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }

    String token  = httpServletRequest.getHeader(UserConstant.HEADER_AUTH);
    if(false == redisService.delToken(token)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"token过期或不存在");
    }

    return ResultUtils.success(true);
  }

  @Override
  public UserVO getVOById(Long id) {
    return getBaseMapper().getVOById(id);
  }

  @Override
  public BaseResponse<UserVO> getInfo() {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }

    return ResultUtils.success(userVO);
  }

  @Override
  public BaseResponse<UserVO> getInfoById(Long id) {
    User u = lambdaQuery()
        .select(User::getId,User::getNickname,User::getAvatar,User::getRole)
        .eq(User::getId,id).one();
    UserVO vo = new UserVO();
    BeanUtils.copyProperties(u,vo);
    return ResultUtils.success(vo);
  }

  @Override
  public BaseResponse<Boolean> updateMe(UserUpdateRequest userUpdateRequest,HttpServletRequest httpServletRequest) {
    // 校验已登录
    UserVO userVO = UserUtils.LoginCheck();
    if( userVO== null) {
      throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
    }

    String avatar = userUpdateRequest.getAvatar();
    if(StringUtils.isNotBlank(avatar) && !FileUtils.isImgFileExist(avatar)) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR,"不存在该路径文件");
    }

    long userId = userVO.getId();
    String nickname = userUpdateRequest.getNickname();
    // sql
    boolean result = update().eq("id",userId)
        .set(StringUtils.isNotBlank(avatar),"avatar",avatar)
        .set(StringUtils.isNotBlank(nickname),"nickname",nickname)
        .update();
    ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR,"更新失败");

    // update redis
    String token  = httpServletRequest.getHeader(UserConstant.HEADER_AUTH);
    if(StringUtils.isNotBlank(avatar)) {
      result = redisService.updateUser(token,"avatar",avatar);
      ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR,"更新失败");
    }
    if(StringUtils.isNotBlank(nickname)) {
      result = redisService.updateUser(token,"nickname",nickname);
      ThrowUtils.throwIf(!result,ErrorCode.OPERATION_ERROR,"更新失败");
    }

    return ResultUtils.success(true);
  }


  // private functions:
  private User newUser(String account) {
    User user =new User();
    user.setAccount(account);
    user.setNickname("user_"+account);
    user.setAvatar(UserConstant.USER_DEFAULT_AVATAR);
    return user;
  }


}




